home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 418_02 / rasmol2 / x11win.c < prev   
Encoding:
C/C++ Source or Header  |  1994-03-02  |  44.3 KB  |  1,602 lines

  1. /* x11win.c
  2.  * RasMol2 Molecular Graphics
  3.  * Roger Sayle, February 1994
  4.  * Version 2.3
  5.  */
  6. #ifndef sun386
  7. #include <stdlib.h>
  8. #endif
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <math.h>
  12.  
  13. #include <X11/Xlib.h>
  14. #include <X11/Xutil.h>
  15. #include <X11/Xatom.h>
  16. #include <X11/keysym.h>
  17. #include <X11/cursorfont.h>
  18.  
  19. #define GRAPHICS
  20. #include "rasmol.h"
  21. #include "graphics.h"
  22. #include "bitmaps.h"
  23. #include "command.h"
  24.  
  25.  
  26. #ifdef DIALBOX
  27. #include <X11/extensions/XInput.h>
  28.  
  29. static int UseDialLEDs;
  30. static XEventClass DialClass;
  31. static XDevice *Dials;
  32. static XID DialIdent;
  33. static int DialEvent;
  34. static int UseDials;
  35. #endif
  36.  
  37.  
  38. #ifdef MITSHM
  39. #include <sys/types.h>
  40. #include <sys/ipc.h>
  41. #include <sys/shm.h>
  42. #include <X11/extensions/XShm.h>
  43.  
  44. #ifdef __STDC__
  45. Bool XShmQueryExtension( Display* );
  46. #else /* non-ANSI C compiler */
  47. Bool XShmQueryExtension();
  48. #endif
  49.  
  50. XShmSegmentInfo xshminfo;
  51. int SharedMemOption;
  52. int SharedMemFlag;
  53. #endif
  54.  
  55.  
  56. #define ButWide    96
  57. #define ButHigh    32
  58. #define XScrlDial  1 /*1*/
  59. #define YScrlDial  0 /*0*/
  60. #define XScrlSkip  8
  61. #define YScrlSkip  8
  62.  
  63.  
  64. /* Determine Mouse Sensitivity! */
  65. #define IsClose(u,v) (((u)>=(v)-1) && ((u)<=(v)+1))
  66. #define MinHeight    (ButMax*(ButHigh+18)+18)
  67. #define MinWidth     (ButWide+127+32)
  68.  
  69.  
  70. /* Increased point size for NCD X-terminals! */
  71. #define NrmFontMax 4
  72. static char *NrmFont[] = {
  73.         "-*-lucida-bold-r-*-*-12-*",
  74.         "-*-helvetica-bold-r-*-*-12-*",
  75.         "-*-lucida-bold-r-*-*-14-*",
  76.         "-*-helvetica-bold-r-*-*-14-*" };
  77.  
  78. static Cursor cross;
  79. static Cursor arrow;
  80. static Cursor hglass;
  81. static Pixmap Scrl;
  82. static Pixmap tilepix;
  83. static Pixmap uppix, dnpix;
  84. static Pixmap lfpix, rgpix;
  85. static Pixmap ButUp, ButDn;
  86. static XFontStruct *NrmInfo;
  87. static XSetWindowAttributes attr;
  88. static Window XScrlWin, YScrlWin;
  89. static Window MainWin;
  90. static Window CanvWin;
  91. static XWMHints hints;
  92. static Colormap cmap;
  93. static Colormap lmap;
  94. static XImage *image;
  95. static Display *dpy;
  96. static Visual *vis;
  97. static GC gcon;
  98.  
  99. #ifdef EIGHTBIT
  100. static unsigned long Ident[256];
  101. static int IdentCount;
  102. #endif
  103.  
  104.  
  105. static int MouseMode;
  106. static int InitX, InitY;
  107. static int HeldButton;
  108. static int HeldStep;
  109.  
  110. static Window OptWin[ButMax];
  111. static char *OptPtr[ButMax];
  112. static int OptLen[ButMax];
  113. static int OptCount;
  114.  
  115. static int MaxWidth;
  116. static int MaxHeight;
  117. static int MainWide, MainHigh;
  118. static int ScrlX, NewScrlX;
  119. static int ScrlY, NewScrlY;
  120. static int PixDepth;
  121. static int LocalMap;
  122.  
  123.  
  124. /* WM_PROTOCOLS */
  125. static char TkInterp[10];
  126. static Atom DelWinXAtom;
  127. static Atom ProtoXAtom;
  128. static Atom InterpAtom;
  129. static Atom CommAtom;
  130.  
  131.  
  132.  
  133. static void FatalGraphicsError(ptr)
  134.     char *ptr;
  135. {
  136.     char buffer[80];
  137.  
  138.     sprintf(buffer,"Graphics Error: %s!",ptr);
  139.     RasMolFatalExit(buffer);
  140. }
  141.  
  142.  
  143. void AllocateColourMap()
  144. {
  145. #ifdef EIGHTBIT
  146.     static XColor Col;
  147.     register int i,j;
  148.  
  149.     if( LocalMap )
  150.     {   XSetWindowColormap(dpy,MainWin,cmap);
  151.         XSetWindowColormap(dpy,CanvWin,cmap);
  152.         XUninstallColormap(dpy,lmap);
  153.         XFreeColormap(dpy,lmap);
  154.         LocalMap = False;
  155.     } else if( IdentCount )
  156.         XFreeColors(dpy,cmap,Ident,IdentCount,(long)0);
  157.     IdentCount = 0;
  158.  
  159.  
  160.     for( i=0; i<256; i++ )
  161.         if( ULut[i] )
  162.         {   Col.red   = RLut[i]<<8;
  163.             Col.green = GLut[i]<<8;
  164.             Col.blue  = BLut[i]<<8;
  165.             Col.flags = DoRed | DoGreen | DoBlue;
  166.             if( !XAllocColor(dpy,cmap,&Col) )
  167.                 break;
  168.             Ident[IdentCount++] = Col.pixel;
  169.             Lut[i] = Col.pixel;
  170.         }
  171.  
  172.     if( i<256 )
  173.     {   lmap = XCopyColormapAndFree(dpy,cmap);
  174.         LocalMap = True;
  175.  
  176.         for( j=0; j<5; j++ )
  177.         {   Col.red   = RLut[j]<<8;
  178.             Col.green = GLut[j]<<8;
  179.             Col.blue  = BLut[j]<<8;
  180.             XAllocColor(dpy,cmap,&Col);
  181.             Lut[i] = Col.pixel;
  182.         }
  183.  
  184.         for( j=i; j<256; j++ )
  185.             if( ULut[j] )
  186.             {   Col.red   = RLut[j]<<8;
  187.                 Col.green = GLut[j]<<8;
  188.                 Col.blue  = BLut[j]<<8;
  189.                 XAllocColor(dpy,lmap,&Col);
  190.                 Lut[j] = Col.pixel;
  191.             }
  192.         XSetWindowColormap(dpy,MainWin,lmap);
  193.         XSetWindowColormap(dpy,CanvWin,lmap);
  194.         XInstallColormap(dpy,lmap);
  195.     }
  196. #endif
  197.  
  198.     XSetWindowBackground(dpy,CanvWin,(long)Lut[5]);
  199. }
  200.  
  201.  
  202.  
  203. static void OpenCanvas( x, y )
  204.     int x, y;
  205. {
  206.     register unsigned long mask;
  207.  
  208.     mask = CWEventMask;
  209.     attr.event_mask = ExposureMask | ButtonPressMask | ButtonMotionMask 
  210.                     | ButtonReleaseMask;
  211.     attr.cursor = cross;                           mask |= CWCursor;
  212.     attr.background_pixel = Lut[0];                mask |= CWBackPixel;
  213.  
  214.     CanvWin = XCreateWindow(dpy, MainWin, 18, 18, x, y, 0, CopyFromParent,
  215.                             InputOutput, vis, mask, &attr );
  216. }
  217.  
  218.  
  219. static void OpenFonts()
  220. {
  221.     register int i;
  222.     cross = XCreateFontCursor(dpy,XC_tcross);
  223.     arrow = XCreateFontCursor(dpy,XC_top_left_arrow);
  224.  
  225.     for( i=0; i<NrmFontMax; i++ )
  226.         if( (NrmInfo=XLoadQueryFont(dpy,NrmFont[i])) ) 
  227.             return;
  228.     FatalGraphicsError("Unable to find suitable font");
  229. }
  230.  
  231.  
  232. static void OpenCursors()
  233. {
  234.     Pixmap source,mask;
  235.     XColor black,white;
  236.  
  237.     white.red = 65535;     black.red = 0;      
  238.     white.green = 65535;   black.green = 0;
  239.     white.blue = 65535;    black.blue = 0;
  240.      
  241.     white.flags = DoRed | DoGreen | DoBlue;
  242.     black.flags = DoRed | DoGreen | DoBlue;
  243.  
  244.     source = XCreateBitmapFromData(dpy,MainWin,(char*)HGlassData,16,16);
  245.     mask   = XCreateBitmapFromData(dpy,MainWin,(char*)HGlassMask,16,16);
  246.     hglass = XCreatePixmapCursor(dpy,source,mask,&black,&white,7,7);
  247. }
  248.  
  249.  
  250. static void OpenColourMap()
  251. {
  252. #ifdef EIGHTBIT
  253.     static XColor Col;
  254.     register int i;
  255.  
  256.     Col.flags = DoRed | DoGreen | DoBlue;
  257.  
  258.     for( i=0; i<5; i++ )
  259.     {   Col.red   = RLut[i]<<8;
  260.         Col.green = GLut[i]<<8;
  261.         Col.blue  = BLut[i]<<8;
  262.         if( !XAllocColor(dpy,cmap,&Col) )
  263.         {   cmap = XCopyColormapAndFree(dpy,cmap);
  264.             XAllocColor(dpy,cmap,&Col);
  265.         } 
  266.         Lut[i] = Col.pixel;
  267.     }
  268.  
  269.     LocalMap = False;
  270.     IdentCount = 0;
  271.     Lut[5]=Lut[0];
  272. #endif
  273. }
  274.  
  275.  
  276. static int RegisterInterpName( name )
  277.     char *name;
  278. {
  279.     static unsigned char *registry;
  280.     static unsigned long len,left;
  281.     static char buffer[32];
  282.     static int format;
  283.     static Atom type;
  284.  
  285.     register int result;
  286.     register char *ptr;
  287.  
  288.     registry = NULL;
  289.     result = XGetWindowProperty(dpy, RootWindow(dpy,0), InterpAtom,
  290.                                 0, 100000, False, XA_STRING, &type,
  291.                                 &format, &len, &left, ®istry );
  292.  
  293.     if( (result!=Success) || (format!=8) || (type!=XA_STRING) )
  294.     {   if( (type!=None) && registry ) XFree(registry);
  295.  
  296.         sprintf(buffer,"%x %s",MainWin,name);
  297.         XChangeProperty( dpy, RootWindow(dpy,0), InterpAtom, XA_STRING, 
  298.                          8, PropModeReplace, buffer, strlen(buffer)+1 );
  299.         return( True );
  300.     }
  301.  
  302.     ptr = (char*)registry;
  303.     while( *ptr )
  304.     {   /* Skip Window ID */
  305.         while( *ptr++ != ' ' )
  306.             if( !*ptr ) break;
  307.  
  308.         /* Compare Interp Name */
  309.         if( !strcmp(ptr,name) )
  310.         {   XFree(registry);
  311.             return(False);
  312.         }
  313.  
  314.         while( *ptr++ );
  315.     }
  316.  
  317.     XFree(registry);
  318.     sprintf(buffer,"%x %s",MainWin,name);
  319.     XChangeProperty( dpy, RootWindow(dpy,0), InterpAtom, XA_STRING, 
  320.                      8, PropModeAppend, buffer, strlen(buffer)+1 );
  321.     return( True );
  322. }
  323.  
  324.  
  325. static void DeRegisterInterpName( name )
  326.     char *name;
  327. {
  328.     static unsigned char *registry;
  329.     static unsigned long len,left;
  330.     static int format;
  331.     static Atom type;
  332.  
  333.     register char *src, *dst;
  334.     register int result;
  335.  
  336.     registry = NULL;
  337.     result = XGetWindowProperty(dpy, RootWindow(dpy,0), InterpAtom,
  338.                                 0, 100000, False, XA_STRING, &type,
  339.                                 &format, &len, &left, ®istry );
  340.     if( type==None )
  341.         return;
  342.  
  343.     if( (result!=Success) || (format!=8) || (type!=XA_STRING) )
  344.     {   XDeleteProperty( dpy, RootWindow(dpy,0), InterpAtom );
  345.         if( registry ) XFree(registry);
  346.         return;
  347.     }
  348.  
  349.     dst = (char*)registry;
  350.     while( *dst )
  351.     {   /* Skip Window ID */
  352.         src = dst;
  353.         while( *src++ != ' ' )
  354.             if( !*src ) break;
  355.  
  356.         /* Compare Interp Name */
  357.         if( strcmp(src,name) )
  358.         {   while( *dst++ );
  359.         } else break;
  360.     }
  361.  
  362.     if( *dst )
  363.     {   /* Skip Interp Name */
  364.         while( *src++ );
  365.         
  366.         /* Shuffle Registry */
  367.         while( *src )
  368.             while( (*dst++ = *src++) );
  369.         *dst = 0;
  370.  
  371.         XChangeProperty( dpy, RootWindow(dpy,0), InterpAtom, XA_STRING,
  372.                          8, PropModeReplace, registry, dst-(char*)registry );
  373.     }
  374.     XFree( registry );
  375. }
  376.  
  377.  
  378. static void OpenIPCComms()
  379. {
  380.     register int i;
  381.  
  382.     CommAtom = XInternAtom( dpy, "Comm", False );
  383.     DelWinXAtom = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  384.     /* XSetWMProtocols(dpy,MainWin,&DelWinXAtom,True); */
  385.     if( (ProtoXAtom = XInternAtom(dpy,"WM_PROTOCOLS",False)) )
  386.         XChangeProperty( dpy, MainWin, ProtoXAtom, XA_ATOM, 32, 
  387.                         PropModeReplace, (Byte*)&DelWinXAtom, True );
  388.  
  389.     InterpAtom = XInternAtom( dpy, "InterpRegistry", False );
  390.  
  391.     XGrabServer( dpy );
  392.     if( !RegisterInterpName("rasmol") )
  393.     {   strcpy(TkInterp,"rasmol #0");
  394.         for( i=1; i<10; i++ )
  395.         {    TkInterp[8] = i+'0';
  396.              if( RegisterInterpName(TkInterp) )
  397.                  break;
  398.         }
  399.  
  400.         if( i==10 ) *TkInterp = 0;
  401.     } else strcpy(TkInterp,"rasmol");
  402.     XUngrabServer( dpy );
  403. }
  404.  
  405.  
  406. static void DrawBox(wdw,pos,x1,y1,x2,y2)
  407.     Drawable wdw; int pos,x1,y1,x2,y2;
  408. {
  409.     register unsigned long colour;
  410.     register int ux,uy,lx,ly;
  411.     register int index;
  412.  
  413.     lx=x1; ly=y1; ux=x2; uy=y2;
  414.     colour = Lut[pos? 3 : 1 ];
  415.     XSetForeground(dpy,gcon,colour);
  416.     for( index=0; index<3; index++ )
  417.     {   XDrawLine(dpy,wdw,gcon,lx,ly,ux,ly);
  418.         XDrawLine(dpy,wdw,gcon,lx,ly,lx,uy);
  419.         lx++; ly++; ux--; uy--;
  420.     }
  421.  
  422.     
  423.     lx=x1; ly=y1; ux=x2; uy=y2;
  424.     colour = Lut[pos? 1 : 3 ];
  425.     XSetForeground(dpy,gcon,colour);
  426.     for( index=0; index<3; index++ )
  427.     {   XDrawLine(dpy,wdw,gcon,ux,ly,ux,uy);
  428.         XDrawLine(dpy,wdw,gcon,lx,uy,ux,uy);
  429.         lx++; ly++; ux--; uy--;
  430.     }
  431. }
  432.  
  433.  
  434. static void OpenButtons()
  435. {
  436.     register unsigned long mask;
  437.     register int index;
  438.  
  439.     ButUp = XCreatePixmap( dpy, MainWin, ButWide+8, ButHigh+8, PixDepth );
  440.     ButDn = XCreatePixmap( dpy, MainWin, ButWide+8, ButHigh+8, PixDepth );
  441.  
  442.     XSetForeground( dpy, gcon, (unsigned long)Lut[2] );
  443.     XFillRectangle( dpy, ButUp, gcon, 0, 0, ButWide+7, ButHigh+7 );
  444.     XFillRectangle( dpy, ButDn, gcon, 0, 0, ButWide+7, ButHigh+7 );
  445.  
  446.     XSetForeground( dpy, gcon, (unsigned long)Lut[0] );
  447.     XDrawRectangle( dpy, ButUp, gcon, 0, 0, ButWide+7, ButHigh+7 );
  448.     XDrawRectangle( dpy, ButDn, gcon, 0, 0, ButWide+7, ButHigh+7 );
  449.     
  450.     DrawBox( ButUp, True,  1, 1, ButWide+6, ButHigh+6 );
  451.     DrawBox( ButDn, False, 1, 1, ButWide+6, ButHigh+6 );
  452.  
  453.  
  454.     mask = CWEventMask;
  455.     attr.event_mask = ButtonPressMask | ButtonReleaseMask;
  456.  
  457.     for( index=0; index<ButMax; index++ )
  458.         OptWin[index] = XCreateWindow( dpy, MainWin,
  459.                                        XRange+58, index*(ButHigh+18)+15,
  460.                                        ButWide+6, ButHigh+6, 0,
  461.                                        CopyFromParent, InputOnly, vis,
  462.                                        mask, &attr );
  463.     OptCount = 0;
  464. }
  465.  
  466.  
  467. static void ReDrawButton( num, pos )
  468.     int num, pos;
  469. {
  470.     register int deltaX, deltaY;
  471.     register int xpos, ypos;
  472.  
  473.     xpos = XRange+61;
  474.     ypos = num*(ButHigh+18)+18;
  475.  
  476.     deltaY = (ButHigh-(NrmInfo->ascent+NrmInfo->descent))/2+NrmInfo->ascent;
  477.     deltaX = (ButWide-XTextWidth(NrmInfo,OptPtr[num],OptLen[num]))/2;
  478.  
  479.     XSetFont( dpy, gcon, NrmInfo->fid );
  480.     XSetForeground( dpy, gcon, (unsigned long)Lut[0] );
  481.     XCopyArea( dpy, pos? ButUp : ButDn, MainWin, gcon,
  482.                0, 0, ButWide+8, ButHigh+8, xpos-4, ypos-4 );
  483.     XDrawString( dpy, MainWin, gcon, xpos+deltaX, ypos+deltaY, 
  484.                  OptPtr[num], OptLen[num] );
  485.     XFlush(dpy);
  486. }
  487.  
  488.  
  489. void NewMenu( num, option )
  490.     int num; char **option;
  491. {
  492.     register char *ptr;
  493.     register int start,stop;
  494.     register int index;
  495.     register int len;
  496.  
  497.     for( index=0; index<num; index++ )
  498.     {   len = 0;
  499.         OptPtr[index] = ptr = *option++;
  500.         while( *ptr++ ) len++;
  501.         OptLen[index] = len;
  502.  
  503.         ReDrawButton( index, True );
  504.     }
  505.     MenuDisable = False;
  506.     OptCount = num;
  507.  
  508.     if( num<ButMax )
  509.     {    start = num*(ButHigh+18)+13;
  510.          stop = ButMax*(ButHigh+18)+5;
  511.          XSetForeground(dpy,gcon,(unsigned long)Lut[2]);
  512.          XFillRectangle( dpy, MainWin, gcon, 
  513.                          XRange+56, start, ButWide+10, stop-start );
  514.     }
  515.     XSync(dpy,False);
  516. }
  517.  
  518.  
  519. static void OpenScrollBars()
  520. {
  521.     register unsigned long mask;
  522.  
  523.     Scrl = XCreatePixmap( dpy, MainWin, 16, 16, PixDepth );
  524.     XSetForeground(dpy,gcon,(unsigned long)Lut[2]); 
  525.     XFillRectangle(dpy,Scrl,gcon,0,0,15,15);
  526.     XSetForeground(dpy,gcon,(unsigned long)Lut[0]); 
  527.     XDrawRectangle(dpy,Scrl,gcon,0,0,15,15);
  528.     DrawBox( Scrl, True, 1, 1, 14, 14 );
  529.  
  530.     tilepix = XCreatePixmapFromBitmapData( dpy, MainWin, (char*)ScrlTile,
  531.                                            8, 8, Lut[0], Lut[2], PixDepth );
  532.  
  533.     mask = CWEventMask;
  534.     attr.event_mask = ExposureMask | ButtonPressMask | ButtonMotionMask 
  535.                     | ButtonReleaseMask;
  536.     attr.background_pixmap = tilepix;              mask |= CWBackPixmap;
  537.  
  538.     XScrlWin = XCreateWindow( dpy, MainWin, 18, YRange+27, XRange, 16, 0,
  539.                               CopyFromParent, InputOutput, vis, mask, &attr );
  540.     lfpix = XCreatePixmapFromBitmapData( dpy, MainWin, (char*)LfArrow,
  541.                                          16, 16, Lut[0], Lut[2], PixDepth );
  542.     rgpix = XCreatePixmapFromBitmapData( dpy, MainWin, (char*)RgArrow,
  543.                                          16, 16, Lut[0], Lut[2], PixDepth );
  544.  
  545.  
  546.     YScrlWin = XCreateWindow( dpy, MainWin, XRange+27, 18, 16, YRange, 0,
  547.                               CopyFromParent, InputOutput, vis, mask, &attr );
  548.     uppix = XCreatePixmapFromBitmapData( dpy, MainWin, (char*)UpArrow,
  549.                                          16, 16, Lut[0], Lut[2], PixDepth );
  550.     dnpix = XCreatePixmapFromBitmapData( dpy, MainWin, (char*)DnArrow,
  551.                                          16, 16, Lut[0], Lut[2], PixDepth );
  552.  
  553.     ScrlX = (XRange/2)-8;
  554.     ScrlY = (YRange/2)-8;
  555. }
  556.  
  557. static void ReDrawXScroll()
  558. {
  559.     XCopyArea(dpy,rgpix,XScrlWin,gcon,0,0,16,16,XRange-16,0);
  560.     XCopyArea(dpy,Scrl ,XScrlWin,gcon,0,0,16,16,ScrlX,0);
  561.     XCopyArea(dpy,lfpix,XScrlWin,gcon,0,0,16,16,0,0);
  562. }
  563.  
  564. static void ReDrawYScroll()
  565. {
  566.     XCopyArea(dpy,dnpix,YScrlWin,gcon,0,0,16,16,0,YRange-16);
  567.     XCopyArea(dpy,Scrl ,YScrlWin,gcon,0,0,16,16,0,ScrlY);
  568.     XCopyArea(dpy,uppix,YScrlWin,gcon,0,0,16,16,0,0);
  569. }
  570.  
  571.  
  572. void UpdateScrollBars()
  573. {
  574.     register int temp;
  575.  
  576.     temp = (DialValue[YScrlDial]+1.0)*(YRange-48);  
  577.     NewScrlY = (temp>>1)+16;
  578.  
  579.     if( NewScrlY != ScrlY )
  580.     {   XClearArea(dpy,YScrlWin,0,ScrlY,16,16,False);
  581.         XCopyArea(dpy,Scrl,YScrlWin,gcon,0,0,16,16,0,NewScrlY);
  582.         ReDrawFlag |= (1<<YScrlDial);
  583.         ScrlY = NewScrlY; 
  584.     }
  585.  
  586.     temp = (DialValue[XScrlDial]+1.0)*(XRange-48);  
  587.     NewScrlX = (temp>>1)+16;
  588.  
  589.     if( NewScrlX != ScrlX )
  590.     {   XClearArea(dpy,XScrlWin,ScrlX,0,16,16,False);
  591.         XCopyArea(dpy,Scrl,XScrlWin,gcon,0,0,16,16,NewScrlX,0);
  592.         ReDrawFlag |= (1<<XScrlDial);
  593.         ScrlX = NewScrlX;
  594.     }
  595.     XFlush(dpy);
  596. }
  597.  
  598.  
  599.  
  600. #ifdef DIALBOX
  601. static void SetDialLabel( num, ptr )
  602.     int num; char *ptr;
  603. {
  604.     static XStringFeedbackControl ctrl;
  605.     static KeySym text[8];
  606.     register int length;
  607.  
  608.     length = 0;
  609.     while( *ptr )
  610.        text[length++] = *ptr++;
  611.  
  612.     ctrl.id = num;
  613.     ctrl.class = DialIdent;
  614.     ctrl.num_keysyms = length;
  615.     ctrl.syms_to_display = text;
  616.     XChangeFeedbackControl(dpy,Dials,DvString,&ctrl);
  617. }
  618.  
  619.  
  620. static void OpenDialsBox()
  621. {
  622.     register XFeedbackState *list;
  623.     register XFeedbackState *feed;
  624.     register XDeviceInfo *devlist;
  625.     register XDeviceInfo *ptr;
  626.     register Atom devtype;
  627.     register int index;
  628.     static int count;
  629.  
  630.     UseDials = False;
  631.     devlist = XListInputDevices(dpy,&count);
  632.     devtype = XInternAtom(dpy,XI_KNOB_BOX,True );
  633.     if( (devtype==None) || !devlist ) return;
  634.  
  635.     ptr = devlist;
  636.     for( index=0; index<count; index++ )
  637.         if( (ptr->use==IsXExtensionDevice) && (ptr->type==devtype) )
  638.         {   Dials = XOpenDevice(dpy,ptr->id);
  639.             DialIdent = ptr->inputclassinfo->class;
  640.             UseDials = True;
  641.             break;
  642.         } else ptr++;
  643.     /* XFreeDeviceList(devlist); */
  644.     if( !UseDials ) return;
  645.  
  646.     UseDialLEDs = 0;
  647.     feed = list = XGetFeedbackControl( dpy, Dials, &count );
  648.     for( index=0; index<count; index++ )
  649.     {   if( feed->class == StringFeedbackClass )
  650.             UseDialLEDs++;
  651.         feed = (XFeedbackState*)(((char*)feed) + feed->length);
  652.     }
  653.     XFreeFeedbackList( list );
  654.  
  655.     if( UseDialLEDs >= 8 )
  656.     {   SetDialLabel(0,"ROTATE X");
  657.         SetDialLabel(1,"ROTATE Y");
  658.         SetDialLabel(2,"ROTATE Z");
  659.         SetDialLabel(3,"  ZOOM  ");
  660.  
  661.         SetDialLabel(4,"TRANS X ");
  662.         SetDialLabel(5,"TRANS Y ");
  663.         SetDialLabel(6,"TRANS Z ");
  664.         SetDialLabel(7,"  SLAB  ");
  665.     } else UseDialLEDs = False;
  666.  
  667.     DeviceMotionNotify( Dials, DialEvent, DialClass );
  668.     XSelectExtensionEvent( dpy, MainWin, &DialClass, 1 );
  669.     XSelectExtensionEvent( dpy, CanvWin, &DialClass, 1 );
  670.     XSelectExtensionEvent( dpy, XScrlWin, &DialClass, 1 );
  671.     XSelectExtensionEvent( dpy, YScrlWin, &DialClass, 1 );
  672.  
  673.     for( index=0; index<ButMax; index++ )
  674.        XSelectExtensionEvent( dpy, OptWin[index], &DialClass, 1 );
  675. }
  676.  
  677.  
  678. static void HandleDialEvent( ptr )
  679.     XDeviceMotionEvent *ptr;
  680. {
  681.     register double temp;
  682.     register int count;
  683.     register int value;
  684.     register int index;
  685.     register int num;
  686.  
  687.     /* Limit Number of Dials */
  688.     count = 8 - ptr->first_axis;
  689.     if( count > ptr->axes_count )
  690.         count = ptr->axes_count;
  691.  
  692.     for( index=0; index<count; index++ )
  693.         if( value = ptr->axis_data[index] )
  694.         {   num = ptr->first_axis+index;
  695.             temp = DialValue[num]+(value/1024.0);
  696.             ReDrawFlag |= (1<<num);
  697.  
  698.             if( num<3 )
  699.             {   while( temp<-1.0 ) temp += 2.0;
  700.                 while( temp>1.0 )  temp -= 2.0;
  701.             } else
  702.             {   if( temp<-1.0 ) temp = -1.0;
  703.                 if( temp>1.0 )  temp = 1.0;
  704.             }
  705.             DialValue[num] = temp;
  706.  
  707.             if( num==YScrlDial )
  708.             {   value = (temp+1.0)*(YRange-48);
  709.                 NewScrlY = (value>>1)+16;
  710.             }
  711.  
  712.             if( num==XScrlDial )
  713.             {   value = (temp+1.0)*(XRange-48);
  714.                 NewScrlX = (value>>1)+16;
  715.             }
  716.         }
  717. }
  718. #endif
  719.  
  720.  
  721. static void ReDrawMain()
  722. {
  723.     register int index;
  724.  
  725.     DrawBox(MainWin,True,0,0,MainWide,MainHigh);
  726.     DrawBox(MainWin,False,15,15,XRange+20,YRange+20);
  727.     DrawBox(MainWin,False,XRange+24,15,XRange+45,YRange+20);
  728.     DrawBox(MainWin,False,15,YRange+24,XRange+20,YRange+45);
  729.  
  730.     for( index=0; index<OptCount; index++ )
  731.         ReDrawButton( index, True );
  732. }
  733.  
  734.  
  735. static void ReSizeWindow( wide, high )
  736.     int wide, high;
  737. {
  738.     register Real xpos;
  739.     register Real ypos;
  740.     register int index;
  741.  
  742.     xpos = (XRange>48)? (Real)(ScrlX-16)/(XRange-48) : 0.0;
  743.     ypos = (YRange>48)? (Real)(ScrlY-16)/(YRange-48) : 0.0;
  744.  
  745.     wide = (wide & ~3) | ((ButWide+79) & 3);
  746.     MainWide = wide;  XRange = wide-(ButWide+79);  WRange = XRange>>1;
  747.     MainHigh = high;  YRange = high-61;            HRange = YRange>>1;
  748.     Range = MinFun(XRange,YRange);
  749.  
  750.     XResizeWindow( dpy, CanvWin, XRange, YRange);
  751.     XMoveResizeWindow( dpy, XScrlWin, 18, YRange+27, XRange, 16 );
  752.     XMoveResizeWindow( dpy, YScrlWin, XRange+27, 18, 16, YRange );
  753.  
  754.     for( index=0; index<ButMax; index++ )
  755.         XMoveWindow( dpy, OptWin[index], XRange+58, index*(ButHigh+18)+15 );
  756.  
  757.     NewScrlX = ScrlX = (xpos*(XRange-48))+16;
  758.     NewScrlY = ScrlY = (ypos*(YRange-48))+16;
  759.  
  760.     XClearWindow( dpy, MainWin );
  761.     XClearWindow( dpy, CanvWin );
  762.  
  763.     ReDrawXScroll();
  764.     ReDrawYScroll();
  765.     ReDrawMain();
  766.  
  767.     ReDrawFlag |= RFReSize;
  768.     XSync(dpy,True);
  769. }
  770.  
  771.  
  772. int FatalXError( ptr )
  773.     Display *ptr;
  774. {
  775.     dpy = (Display*)NULL;
  776.     RasMolFatalExit("*** Fatal X11 I/O Error! ***");
  777.     /* Avoid Compilation Warnings! */
  778.     return( (int)ptr );
  779. }
  780.  
  781.  
  782. int OpenDisplay( x, y )
  783.     int x, y;
  784. {
  785.     register int i,num;
  786.     register char *ptr;
  787.     register unsigned long mask;
  788.     static XVisualInfo visinfo;
  789.     static XSizeHints size;
  790.     static Window rootwin;
  791.     static Pixmap icon;
  792.  
  793.  
  794.     image = (XImage*)NULL;
  795.  
  796.     MouseMode = MMRasMol;
  797.     UseHourGlass = True;
  798.     MenuDisable = False;
  799.     HeldButton = -1;
  800.  
  801.     for( i=0; i<8; i++ )
  802.          DialValue[i] = 0.0;
  803.  
  804. #ifdef EIGHTBIT
  805.     RLut[0]=0;   GLut[0]=0;   BLut[0]=0;    ULut[0]=True;
  806.     RLut[1]=100; GLut[1]=100; BLut[1]=100;  ULut[1]=True;
  807.     RLut[2]=150; GLut[2]=150; BLut[2]=150;  ULut[2]=True;
  808.     RLut[3]=200; GLut[3]=200; BLut[3]=200;  ULut[3]=True;
  809.     RLut[4]=255; GLut[4]=255; BLut[4]=255;  ULut[4]=True;
  810. #else
  811.     Lut[0] = 65793*0;
  812.     Lut[1] = 65793*64;
  813.     Lut[2] = 65793*128;
  814.     Lut[3] = 65793*196;
  815.     Lut[4] = 65793*255;
  816. #endif
  817.  
  818.     XRange = x;  WRange = XRange>>1;
  819.     YRange = y;  HRange = YRange>>1;
  820.     Range = MinFun(XRange,YRange);
  821.  
  822.     if( (dpy=XOpenDisplay(NULL)) == NULL )
  823.         return( 0 );
  824.  
  825.     num = DefaultScreen(dpy);
  826.     rootwin = RootWindow(dpy,num);
  827.     XSetIOErrorHandler( FatalXError );
  828.  
  829. #ifdef EIGHTBIT
  830.     if( !XMatchVisualInfo(dpy,num,8,PseudoColor,&visinfo) )
  831.     {   XCloseDisplay(dpy);
  832.         return(0);
  833.     } else PixDepth = 8;
  834. #else
  835.     if( XMatchVisualInfo(dpy,num,32,TrueColor,&visinfo) )
  836.     {   PixDepth = 32;
  837.     } else if( XMatchVisualInfo(dpy,num,24,TrueColor,&visinfo) )
  838.     {   PixDepth = 24;
  839.     } else /* No suitable display! */
  840.     {   XCloseDisplay(dpy);
  841.         return(0);
  842.     }
  843. #endif
  844.  
  845.     vis = visinfo.visual;
  846.     if( vis != DefaultVisual(dpy,num) )
  847.     {   cmap = XCreateColormap(dpy,rootwin,vis,AllocNone);
  848.     } else cmap = DefaultColormap(dpy,num);
  849.  
  850.     OpenFonts();
  851.     OpenColourMap();
  852.  
  853.     MaxWidth = DisplayWidth(dpy,num);
  854.     MaxHeight = DisplayHeight(dpy,num);
  855.     MainWide = x+ButWide+79;
  856.     MainHigh = y+61;
  857.  
  858.     mask = CWEventMask;
  859.     attr.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask
  860.                     | EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
  861.     attr.background_pixel = Lut[2];     mask |= CWBackPixel;
  862.     attr.border_pixel = Lut[2];         mask |= CWBorderPixel;
  863.     attr.colormap = cmap;               mask |= CWColormap;
  864.     attr.cursor = arrow;                mask |= CWCursor;
  865.  
  866.     MainWin = XCreateWindow(dpy, rootwin, 0, 0, MainWide, MainHigh, 2,
  867.                 PixDepth, InputOutput, vis, mask, &attr );
  868.  
  869.     gcon = XCreateGC(dpy,MainWin,0L,NULL);
  870.     /* DefaultGC(dpy,num) */
  871.  
  872.     XSetGraphicsExposures(dpy,gcon,False);
  873.     icon = XCreateBitmapFromData(dpy,MainWin,(char*)icon_bits,
  874.                                  icon_width,icon_height );
  875.  
  876.     size.flags = PMinSize | PMaxSize;
  877.     size.min_width = MinWidth;    size.max_width = MaxWidth;
  878.     size.min_height = MinHeight;  size.max_height = MaxHeight;
  879.     XSetStandardProperties(dpy, MainWin, "RasMol Version 2.3",
  880.                            "RasMol", icon, NULL, 0, &size );
  881.  
  882.     hints.icon_pixmap = icon;
  883.     hints.flags = IconPixmapHint;
  884.     XSetWMHints(dpy,MainWin,&hints);
  885.  
  886.     OpenCanvas( x, y );
  887.     OpenScrollBars();
  888.     OpenCursors();
  889.     OpenButtons();
  890.     OpenIPCComms();
  891.  
  892. #ifdef DIALBOX
  893.     OpenDialsBox();
  894. #endif
  895.  
  896. #ifdef MITSHM
  897.     ptr = DisplayString(dpy);
  898.     if( !ptr || (*ptr==':') || !strncmp(ptr,"localhost:",10) || 
  899.         !strncmp(ptr,"unix:",5) || !strncmp(ptr,"local:",6) )
  900.     {   SharedMemOption = XShmQueryExtension(dpy);
  901.     } else SharedMemOption = False;
  902.     SharedMemFlag = False;
  903. #endif
  904.  
  905.     XMapSubwindows(dpy,MainWin);
  906.     XMapWindow(dpy,MainWin);
  907.  
  908.     ReDrawMain();
  909.     ReDrawXScroll();
  910.     ReDrawYScroll();
  911.     XSync(dpy,False);
  912.  
  913.     return( ConnectionNumber(dpy) );
  914. }
  915.  
  916.  
  917. #ifdef MITSHM
  918. Pixel *AllocSharedMem( size )
  919.     int size;
  920. {
  921.     register Pixel *ptr;
  922.  
  923.     SharedMemFlag = False;
  924.     if( SharedMemOption )
  925.  
  926.     if( !SharedMemFlag ) 
  927.         ptr = (Pixel*)malloc(size);
  928.     return( ptr );
  929. }
  930.  
  931.  
  932. void FreeSharedMem( ptr )
  933.     Pixel *ptr;
  934. {
  935.     if( SharedMemFlag )
  936.     {   XShmDetach(dpy,&xshminfo);
  937.         shmdt(xshminfo.shmaddr);
  938.     } else free( ptr );
  939. }
  940. #endif
  941.  
  942.  
  943.  
  944. Pixel *CreateImage()
  945. {
  946.     register Long size, temp;
  947.     register Pixel *ptr;
  948.  
  949.     if( image ) 
  950.     {
  951. #ifdef MITSHM
  952.         if( SharedMemFlag )
  953.         {   XShmDetach( dpy, &xshminfo );
  954.             image->data = (char*)NULL;
  955.             shmdt( xshminfo.shmaddr );
  956.         }
  957. #endif
  958.         XDestroyImage( image );
  959.     }
  960.  
  961.     size = (Long)XRange*YRange*sizeof(Pixel) + 32;
  962.  
  963. #ifdef MITSHM
  964.     if( SharedMemOption )
  965.     {   SharedMemFlag = False;
  966.         image = XShmCreateImage( dpy, vis, PixDepth, ZPixmap, 
  967.                                  NULL, &xshminfo, XRange, YRange );
  968.         if( image )
  969.         {   temp = (Long)image->bytes_per_line * image->height;
  970.             if( temp > size ) size = temp;
  971.             xshminfo.shmid = shmget( IPC_PRIVATE, size, IPC_CREAT|0777 );
  972.             if( xshminfo.shmid != -1 ) 
  973.             {   xshminfo.shmaddr = (char*)shmat(xshminfo.shmid,0,0);
  974.                 if( xshminfo.shmaddr != (char*)-1 )
  975.                 {   image->data = xshminfo.shmaddr;
  976.                     ptr = (Pixel*)xshminfo.shmaddr;
  977.                     xshminfo.readOnly = True;
  978.  
  979.                     SharedMemFlag = XShmAttach( dpy, &xshminfo );
  980.                     XSync(dpy,False);
  981.                 }
  982.                 /* Always Destroy Shared Memory Ident */
  983.                 shmctl( xshminfo.shmid, IPC_RMID, 0 );
  984.             }
  985.  
  986.             if( !SharedMemFlag )
  987.             {   XDestroyImage( image );
  988.             } else return( ptr );
  989.         }
  990.     }
  991.  
  992. #endif
  993.     if( (ptr = (Pixel*)malloc( size )) )
  994.     {   image = XCreateImage( dpy, vis, PixDepth, ZPixmap, 0, (char*)ptr, 
  995.                               XRange, YRange, ((PixDepth>8)?32: 8) , 0 );
  996.         if( !image ) return( (Pixel*)NULL );
  997.     } else image = (XImage*)NULL;
  998.     return( ptr );
  999. }
  1000.  
  1001.  
  1002. void TransferImage()
  1003. {   
  1004. #ifdef MITSHM
  1005.     if( SharedMemFlag )
  1006.     {   XShmPutImage(dpy,CanvWin,gcon,image,0,0,0,0,XRange,YRange,False);
  1007.     } else
  1008. #endif
  1009.     XPutImage( dpy, CanvWin, gcon, image, 0, 0, 0, 0, XRange, YRange );
  1010.     XFlush(dpy);
  1011. }
  1012.  
  1013.  
  1014. void ClearImage()
  1015. {
  1016.     XClearWindow( dpy, CanvWin );
  1017.     XFlush(dpy);
  1018. }
  1019.  
  1020. static int HandleIPCError( disp, ptr )
  1021.     Display *disp;  XErrorEvent *ptr;
  1022. {
  1023.     return( 0 );
  1024. }
  1025.  
  1026.  
  1027. static void HandleIPCCommand()
  1028. {
  1029.     static unsigned long len,left;
  1030.     static unsigned char *command;
  1031.     static Window source;
  1032.     static int serial;
  1033.     static int format;
  1034.     static Atom type;
  1035.     char buffer[32];
  1036.     int (*handler)();
  1037.  
  1038.     register int result;
  1039.     register char *ptr;
  1040.  
  1041.     command = NULL;
  1042.     result = XGetWindowProperty( dpy, MainWin, CommAtom, 0, 1024, True, 
  1043.                                  XA_STRING, &type, &format, &len, &left,
  1044.                                  &command );
  1045.     if( (result!=Success) || (type!=XA_STRING) || (format!=8) )
  1046.     {   if( command ) XFree(command);
  1047.         return;
  1048.     }
  1049.  
  1050.     result = 0;
  1051.     ptr = (char*)command;
  1052.     while( *ptr )
  1053.     {   if( *ptr=='C' )
  1054.         {   sscanf(ptr+1,"%x %x\n",&source,&serial);
  1055.             while( *ptr && (*ptr!='|') ) ptr++;
  1056.             if( *ptr=='|' )
  1057.             {   result = ExecuteIPCCommand(ptr+1);
  1058.             } else result = 0;
  1059.  
  1060.             sprintf(buffer,"R %x 0 %d",serial,result);
  1061.             handler = XSetErrorHandler( HandleIPCError );
  1062.             XChangeProperty( dpy, source, CommAtom, XA_STRING, 8,
  1063.                              PropModeAppend, buffer, strlen(buffer)+1 );
  1064.             XSync(dpy,False);
  1065.             XSetErrorHandler(handler);
  1066.         } 
  1067.  
  1068.         /* Next Command! */
  1069.         while( *ptr++ );
  1070.     }
  1071.     XFree(command);
  1072.  
  1073.     if( result==2 )
  1074.         RasMolExit();
  1075. }
  1076.  
  1077.  
  1078. static int CropRange( val, min, max )
  1079.     int val, min, max;
  1080. {
  1081.     if( val<min ) return( min );
  1082.     if( val>max ) return( max );
  1083.     return( val );
  1084. }
  1085.  
  1086.  
  1087. static void ClampDial( dial, value )
  1088.     int dial;  Real value;
  1089. {
  1090.     register Real temp;
  1091.  
  1092.     temp = DialValue[dial] + value;
  1093.  
  1094.     if( temp > 1.0 )
  1095.     {   DialValue[dial] = 1.0;
  1096.     } else if( temp < -1.0 )
  1097.     {   DialValue[dial] = -1.0;
  1098.     } else DialValue[dial] = temp;
  1099. }
  1100.  
  1101.  
  1102. static void WrapDial( dial, value )
  1103.     int dial;  Real value;
  1104. {
  1105.     register Real temp;
  1106.  
  1107.     temp = DialValue[dial] + value;
  1108.     while( temp < -1.0 )  temp += 2.0;
  1109.     while( temp > 1.0 )   temp -= 2.0;
  1110.     DialValue[dial] = temp;
  1111. }
  1112.  
  1113.  
  1114. void SetMouseMode( mode )
  1115. {
  1116.     if( mode==MouseMode )
  1117.         return;
  1118.  
  1119.     if( (mode==MMQuanta) || (MouseMode==MMQuanta) )
  1120.     {   /* Enable/Disable Pointer Motion Events! */
  1121.         attr.event_mask = ExposureMask | ButtonPressMask | ButtonMotionMask 
  1122.                         | ButtonReleaseMask;
  1123.         if( mode==MMQuanta ) attr.event_mask |= PointerMotionMask;
  1124.         XChangeWindowAttributes( dpy, CanvWin, CWEventMask, &attr );
  1125.     }
  1126.     MouseMode = mode;
  1127. }
  1128.  
  1129.  
  1130. static void MouseMove( status, dx, dy )
  1131.     int status, dx, dy;
  1132. {
  1133.     register int index;
  1134.  
  1135.     if( MouseMode == MMRasMol )
  1136.     {   if( status & ShiftMask )
  1137.         {   if( status & Button1Mask ) 
  1138.             {   if( dy ) /* Zoom Vertical */
  1139.                 {   ClampDial( 3, (Real)dy/HRange );
  1140.                     ReDrawFlag |= RFZoom;
  1141.                 }
  1142.             } else if( status & (Button2Mask|Button3Mask) )
  1143.                 if( dx ) /* Z Rotation Horizontal */
  1144.                 {   WrapDial( 2, (Real)dx/WRange );
  1145.                     ReDrawFlag |= RFRotateZ;
  1146.                 }
  1147.         } else if( status & ControlMask )
  1148.         {   if( status & Button1Mask )
  1149.             {   if( dy ) /* Slab Vertical */
  1150.                 {   ClampDial( 7, (Real)dy/YRange );
  1151.                     ReDrawFlag |= RFSlab;
  1152.                 }
  1153.             }
  1154.  
  1155.         } else /* Unmodified! */
  1156.             if( status & Button1Mask )
  1157.             {   if( dx ) /* Rotate Y Horizontal */
  1158.                 {   WrapDial( 1, (Real)dx/WRange );
  1159.                     index = (DialValue[1]+1.0)*(XRange-48);
  1160.                     NewScrlX = (index>>1)+16;
  1161.                     ReDrawFlag |= RFRotateY;
  1162.                 }
  1163.  
  1164.                 if( dy ) /* Rotate X Vertical */
  1165.                 {   WrapDial( 0, (Real)dy/HRange );
  1166.                     index = (DialValue[0]+1.0)*(YRange-48);
  1167.                     NewScrlY = (index>>1)+16;
  1168.                     ReDrawFlag |= RFRotateX;
  1169.                 }
  1170.             } else if( status & (Button2Mask|Button3Mask) )
  1171.             {   if( dx ) /* Translate X Horizontal */
  1172.                 {   ClampDial( 4, (Real)dx/XRange );
  1173.                     ReDrawFlag |= RFTransX;
  1174.                 }
  1175.  
  1176.                 if( dy ) /* Translate Y Vertical */
  1177.                 {   ClampDial( 5, (Real)dy/YRange );
  1178.                     ReDrawFlag |= RFTransY;
  1179.                 }
  1180.             }
  1181.     } else if( MouseMode==MMQuanta )
  1182.     {   if( status & ShiftMask )
  1183.         {   if( status & Button1Mask )
  1184.             {   if( dy ) /* Slab Vertical */
  1185.                 {   ClampDial( 7, (Real)dy/YRange );
  1186.                     ReDrawFlag |= RFSlab;
  1187.                 }
  1188.             } else if( status & Button2Mask )
  1189.             {   if( dx ) /* Translate X Horizontal */
  1190.                 {   ClampDial( 4, (Real)dx/XRange );
  1191.                     ReDrawFlag |= RFTransX;
  1192.                 }
  1193.  
  1194.                 if( dy ) /* Translate Y Vertical */
  1195.                 {   ClampDial( 5, (Real)dy/YRange );
  1196.                     ReDrawFlag |= RFTransY;
  1197.                 }
  1198.             } else if( !(status & Button3Mask) )
  1199.                 if( dy ) /* Zoom Vertical */
  1200.                 {   ClampDial( 3, (Real)dy/HRange );
  1201.                     ReDrawFlag |= RFZoom;
  1202.                 }
  1203.         } else if( status & Button2Mask )
  1204.         {   if( dx ) /* Rotate Y Horizontal */
  1205.             {   WrapDial( 1, (Real)dx/WRange );
  1206.                 index = (DialValue[1]+1.0)*(XRange-48);
  1207.                 NewScrlX = (index>>1)+16;
  1208.                 ReDrawFlag |= RFRotateY;
  1209.             }
  1210.  
  1211.             if( dy ) /* Rotate X Vertical */
  1212.             {   WrapDial( 0, (Real)dy/HRange );
  1213.                 index = (DialValue[0]+1.0)*(YRange-48);
  1214.                 NewScrlY = (index>>1)+16;
  1215.                 ReDrawFlag |= RFRotateX;
  1216.             }
  1217.         } else if( status & Button3Mask )
  1218.             if( dx ) /* Z Rotation Horizontal */
  1219.             {   WrapDial( 2, (Real)dx/WRange );
  1220.                 ReDrawFlag |= RFRotateZ;
  1221.             }
  1222.     } else /* MMInsight */
  1223.         switch( status & (Button1Mask|Button2Mask|Button3Mask) )
  1224.         {   case( Button1Mask ):
  1225.                     if( dx ) /* Rotate Y Horizontal */
  1226.                     {   WrapDial( 1, (Real)dx/WRange );
  1227.                         index = (DialValue[1]+1.0)*(XRange-48);
  1228.                         NewScrlX = (index>>1)+16;
  1229.                         ReDrawFlag |= RFRotateY;
  1230.                     }
  1231.  
  1232.                     if( dy ) /* Rotate X Vertical */
  1233.                     {   WrapDial( 0, (Real)dy/HRange );
  1234.                         index = (DialValue[0]+1.0)*(YRange-48);
  1235.                         NewScrlY = (index>>1)+16;
  1236.                         ReDrawFlag |= RFRotateX;
  1237.                     }
  1238.                     break;
  1239.  
  1240.             case( Button2Mask ):
  1241.                     if( dx ) /* Translate X Horizontal */
  1242.                     {   ClampDial( 4, (Real)dx/XRange );
  1243.                         ReDrawFlag |= RFTransX;
  1244.                     }
  1245.  
  1246.                     if( dy ) /* Translate Y Vertical */
  1247.                     {   ClampDial( 5, (Real)dy/YRange );
  1248.                         ReDrawFlag |= RFTransY;
  1249.                     }
  1250.                     break;
  1251.  
  1252.             case( Button1Mask|Button2Mask ):
  1253.                     ClampDial( 3, (Real)dx/WRange - (Real)dy/HRange );
  1254.                     ReDrawFlag |= RFZoom;
  1255.                     break;
  1256.  
  1257.             case( Button1Mask|Button3Mask ):
  1258.                     WrapDial( 2, (Real)dx/WRange - (Real)dy/HRange );
  1259.                     ReDrawFlag |= RFRotateZ;
  1260.                     break;
  1261.  
  1262.             case( Button1Mask|Button2Mask|Button3Mask ):
  1263.                     ClampDial( 7, (Real)dx/XRange - (Real)dy/YRange );
  1264.                     ReDrawFlag |= RFSlab;
  1265.                     break;
  1266.         }
  1267. }
  1268.  
  1269.  
  1270. int FetchEvent( wait )
  1271.     int wait;
  1272.     static XEvent event;
  1273.     register Real temp;
  1274.     register int index;
  1275.  
  1276.  
  1277.     NewScrlX = ScrlX;
  1278.     NewScrlY = ScrlY;
  1279.  
  1280.     if( HeldButton != -1 ) 
  1281.         wait = False;
  1282.  
  1283.     while( XPending(dpy) || (wait && !ReDrawFlag) )
  1284.     {   XNextEvent(dpy,&event);
  1285.         switch( event.type )
  1286.         {   case(ButtonPress):
  1287.                 {   XButtonPressedEvent *ptr;
  1288.  
  1289.                     HeldButton = -1;
  1290.                     ptr = (XButtonPressedEvent*)&event;
  1291.                     if( !MenuDisable )
  1292.                         for( index=0; index<OptCount; index++ )
  1293.                             if( ptr->window==OptWin[index] )
  1294.                             {   ReDrawButton( index, False );
  1295.                                 break;
  1296.                             }
  1297.  
  1298.                     if( ptr->window==XScrlWin )
  1299.                     {   wait = False;
  1300.                         if( ptr->x<16 )
  1301.                         {   HeldButton = XScrlDial;
  1302.                             HeldStep = -XScrlSkip;
  1303.                         } else if( ptr->x>=XRange-16 )
  1304.                         {   HeldButton = XScrlDial;
  1305.                             HeldStep = XScrlSkip;
  1306.                         } else
  1307.                         {   index = ptr->x-8;
  1308.                             if( XScrlDial<3 )
  1309.                             {   if( index>XRange-32 ) index -= XRange-48;
  1310.                                 else if( index<16 ) index += XRange-48;
  1311.                                 NewScrlX = index;
  1312.                             } else NewScrlX = CropRange(index,16,XRange-32);
  1313.                         }
  1314.  
  1315.                     } else if( ptr->window==YScrlWin )
  1316.                     {   wait = False;
  1317.                         if( ptr->y<16 )
  1318.                         {   HeldButton = YScrlDial;
  1319.                             HeldStep = -YScrlSkip;
  1320.                         } else if( ptr->y>=YRange-16 )
  1321.                         {   HeldButton = YScrlDial;
  1322.                             HeldStep = YScrlSkip;
  1323.                         } else
  1324.                         {   index = ptr->y-8;
  1325.                             if( YScrlDial<3 )
  1326.                             {   if( index>YRange-32 ) index -= YRange-48;
  1327.                                 else if( index<16 ) index += YRange-48;
  1328.                                 NewScrlY = index;
  1329.                             } else NewScrlY = CropRange(index,16,YRange-32);
  1330.                         }
  1331.  
  1332.                     } else if( ptr->window==CanvWin )
  1333.                     {   InitX = PointX = ptr->x;
  1334.                         InitY = PointY = ptr->y;
  1335.                     }
  1336.                 } break;
  1337.  
  1338.             case(MotionNotify):
  1339.                 {   XMotionEvent *ptr;
  1340.                     int dx, dy;
  1341.  
  1342.                     ptr = (XMotionEvent*)&event;
  1343.                     if( ptr->window==CanvWin )
  1344.                     {   if( !IsClose(ptr->x,InitX) || !IsClose(ptr->y,InitY) )
  1345.                         {   dx = ptr->x-PointX;  dy = ptr->y-PointY;
  1346.                             MouseMove( ptr->state, dx, dy );
  1347.  
  1348.                             PointX = ptr->x;
  1349.                             PointY = ptr->y;
  1350.                         }
  1351.                     } else if( HeldButton == -1 )
  1352.                     {   if( ptr->window==XScrlWin )
  1353.                         {   index = ptr->x-8;
  1354.                             NewScrlX = CropRange(index,16,XRange-32);
  1355.                         } else /* if( ptr->window==YScrlWin ) */
  1356.                         {   index = ptr->y-8;
  1357.                             NewScrlY = CropRange(index,16,YRange-32);
  1358.                         }
  1359.                     }
  1360.                 } break;
  1361.              
  1362.             case(ButtonRelease):
  1363.                 {   XButtonReleasedEvent *ptr;
  1364.  
  1365.             HeldButton = -1;
  1366.                     ptr = (XButtonReleasedEvent*)&event;
  1367.                     if( ptr->window==CanvWin )
  1368.                     {   PointX = ptr->x;  PointY = ptr->y;
  1369.                         if( IsClose(PointX,InitX) && IsClose(PointY,InitY) )
  1370.                             ReDrawFlag |= RFPoint;
  1371.                     } else if( !MenuDisable )
  1372.                         for( index=0; index<OptCount; index++ )
  1373.                             if( ptr->window==OptWin[index] )
  1374.                                 return(index-ButMax);
  1375.  
  1376.                 } break;
  1377.  
  1378.             case(KeyPress):
  1379.                 {   XKeyPressedEvent *ptr;
  1380.                     static KeySym symbol;
  1381.                     static char keychar;
  1382.  
  1383.                     ptr = (XKeyPressedEvent*)&event;
  1384.                     index = XLookupString(ptr,&keychar,1,&symbol,NULL);
  1385.                     switch( symbol )
  1386.                     {   case(XK_Begin):
  1387.                         case(XK_Home):  return( 0x01 );  break;
  1388.                         case(XK_Right): return( 0x06 );  break;
  1389.                         case(XK_Left):  return( 0x02 );  break;
  1390.                         case(XK_End):   return( 0x05 );  break;
  1391.                         case(XK_Up):
  1392.                         case(XK_Prior): return( 0x10 );  break;
  1393.                         case(XK_Down):
  1394.                         case(XK_Next):  return( 0x0e );  break;
  1395.  
  1396.                         default:        if( index==1 ) 
  1397.                                             return( keychar );
  1398.                     }
  1399.                 } break;
  1400.  
  1401.  
  1402.             case(Expose):
  1403.                 {   XExposeEvent *ptr;
  1404.  
  1405.                     ptr = (XExposeEvent*)&event;
  1406.                     if( ptr->window==CanvWin )
  1407.                     {   if( image ) {
  1408. #ifdef MITSHM
  1409.                             if( SharedMemFlag )
  1410.                             {   XShmPutImage( dpy, CanvWin, gcon, image,
  1411.                                               ptr->x, ptr->y, ptr->x, ptr->y,
  1412.                                               ptr->width, ptr->height, False);
  1413.                             } else
  1414. #endif 
  1415.                             XPutImage( dpy, CanvWin, gcon, image,
  1416.                                        ptr->x, ptr->y, ptr->x, ptr->y,
  1417.                                        ptr->width, ptr->height );
  1418.                         }
  1419.                     } else if( ptr->window==MainWin )
  1420.                     {   ReDrawMain();
  1421.                     } else if( ptr->window==XScrlWin )
  1422.                     {   ReDrawXScroll();
  1423.                     } else if( ptr->window==YScrlWin )
  1424.                         ReDrawYScroll();
  1425.                     XSync(dpy,False);
  1426.                 } break;
  1427.  
  1428.             case(EnterNotify):
  1429.                 if( LocalMap )
  1430.                     XInstallColormap(dpy,lmap);
  1431.                 break;
  1432.  
  1433.             case(LeaveNotify):
  1434.                 if( LocalMap )
  1435.                     XUninstallColormap(dpy,lmap);
  1436.                 break;
  1437.  
  1438.             case(ConfigureNotify):
  1439.                 {   XConfigureEvent *ptr;
  1440.                     register int wide,high;
  1441.  
  1442.                     ptr = (XConfigureEvent*)&event;
  1443.                     wide = CropRange(ptr->width, MinWidth, MaxWidth );
  1444.                     high = CropRange(ptr->height,MinHeight,MaxHeight);
  1445.                     if( (wide!=MainWide) || (high!=MainHigh) )
  1446.                         ReSizeWindow(wide,high);
  1447.                      
  1448.                 } break;
  1449.  
  1450.             case(ClientMessage):
  1451.                 {   XClientMessageEvent *ptr;
  1452.  
  1453.                     ptr = (XClientMessageEvent*)&event;
  1454.                     if( (ptr->message_type==ProtoXAtom) && 
  1455.                         (ptr->data.l[0]==DelWinXAtom) )
  1456.                         RasMolExit();
  1457.                 } break;
  1458.  
  1459.             case(PropertyNotify):
  1460.                 {   XPropertyEvent *ptr;
  1461.  
  1462.                     ptr = (XPropertyEvent*)&event;
  1463.                     if( (ptr->atom==CommAtom) &&
  1464.                         (ptr->state==PropertyNewValue) )
  1465.                         HandleIPCCommand();
  1466.                 } break;
  1467.  
  1468.             case(MapNotify):
  1469.                 ReDrawXScroll();
  1470.                 ReDrawYScroll();
  1471.                 ReDrawMain();
  1472.         break;
  1473.  
  1474.             default:  
  1475. #ifdef DIALBOX
  1476.                 if( event.type==DialEvent )
  1477.             HandleDialEvent( &event );
  1478. #endif
  1479.                 break;
  1480.         }
  1481.     }
  1482.  
  1483.     if( HeldButton == YScrlDial )
  1484.     {   index = NewScrlY+HeldStep;
  1485.         if( YScrlDial<3 )
  1486.         {   if( index<16 )             
  1487.             {   index += YRange-48;
  1488.             } else if( index>YRange-32 ) 
  1489.                 index -= YRange-48;
  1490.             NewScrlY = index;
  1491.         } else NewScrlY = CropRange(index,16,YRange-32);
  1492.     }
  1493.  
  1494.     if( NewScrlY != ScrlY )
  1495.     {   XClearArea(dpy,YScrlWin,0,ScrlY,16,16,False);
  1496.         XCopyArea(dpy,Scrl,YScrlWin,gcon,0,0,16,16,0,NewScrlY);
  1497.  
  1498.         temp = ((Real)(NewScrlY-16))/(YRange-48);
  1499.         DialValue[YScrlDial] = 2.0*temp - 1.0;
  1500.         ReDrawFlag |= (1<<YScrlDial);
  1501.         ScrlY = NewScrlY;
  1502.     }
  1503.  
  1504.     if( HeldButton == XScrlDial )
  1505.     {   index = NewScrlX+HeldStep;
  1506.         if( XScrlDial<3 )
  1507.         {   if( index<16 ) 
  1508.             {   index += XRange-48;
  1509.             } else if( index>XRange-32 ) 
  1510.                 index -= XRange-48;
  1511.             NewScrlX = index;
  1512.         } else NewScrlX = CropRange(index,16,XRange-32);
  1513.     }
  1514.  
  1515.     if( NewScrlX != ScrlX )
  1516.     {   XClearArea(dpy,XScrlWin,ScrlX,0,16,16,False);
  1517.         XCopyArea(dpy,Scrl,XScrlWin,gcon,0,0,16,16,NewScrlX,0);
  1518.  
  1519.         temp = ((Real)(NewScrlX-16))/(XRange-48);
  1520.         DialValue[XScrlDial] = 2.0*temp - 1.0;
  1521.         ReDrawFlag |= (1<<XScrlDial);
  1522.         ScrlX = NewScrlX;
  1523.     }
  1524.     XSync(dpy,False);
  1525.     return( 0 );
  1526. }
  1527.  
  1528.  
  1529. int LookUpColour( name, red, grn, blu )
  1530.     char *name; int *red, *grn, *blu;
  1531. {
  1532.     static XColor exact, close;
  1533.     register Colormap map;
  1534.  
  1535.     map = (LocalMap)? lmap : cmap;
  1536.     if( XLookupColor(dpy,map,name,&exact,&close) )
  1537.     {   *red = exact.red>>8;
  1538.         *grn = exact.green>>8;
  1539.         *blu = exact.blue>>8;
  1540.         return(True);
  1541.     } else 
  1542.         return(False);
  1543. }
  1544.  
  1545.  
  1546. void BeginWait()
  1547. {
  1548.     if( UseHourGlass )
  1549.     {   XDefineCursor(dpy,CanvWin,hglass);
  1550.         XDefineCursor(dpy,MainWin,hglass);
  1551.         XFlush(dpy);
  1552.     }
  1553. }
  1554.  
  1555.  
  1556. void EndWait()
  1557. {
  1558.     if( UseHourGlass )
  1559.     {   XDefineCursor(dpy,CanvWin,cross);
  1560.         XDefineCursor(dpy,MainWin,arrow);
  1561.         XFlush(dpy);
  1562.     }
  1563. }
  1564.  
  1565.  
  1566. void CloseDisplay()
  1567. {
  1568. #ifdef DIALBOX
  1569.     register int num;
  1570. #endif
  1571.  
  1572.     /* FatalXError! */
  1573.     if( !dpy ) return;
  1574.  
  1575.     if( image ) 
  1576.     {
  1577. #ifdef MITSHM
  1578.         if( SharedMemFlag )
  1579.         {   XShmDetach( dpy, &xshminfo );
  1580.             image->data = (char*)NULL;
  1581.             shmdt( xshminfo.shmaddr );
  1582.         }
  1583. #endif
  1584.         XDestroyImage( image );
  1585.     }
  1586.  
  1587.     if( *TkInterp )
  1588.     {   XGrabServer( dpy );
  1589.         DeRegisterInterpName(TkInterp);
  1590.         XUngrabServer( dpy );
  1591.     }
  1592.  
  1593. #ifdef DIALBOX
  1594.     if( UseDials && UseDialLEDs )
  1595.         for( num=0; num<8; num++ )
  1596.             SetDialLabel(num,"");
  1597. #endif
  1598.     XCloseDisplay( dpy );
  1599. }
  1600.  
  1601.